package com.wormhole.wormholemanagement.service.impl;

import com.wormhole.wormholemanagement.dto.DocumentNode;
import com.wormhole.wormholemanagement.service.DocumentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;

@Slf4j
@Service
public class DocumentServiceImpl implements DocumentService {

    // 缓存键前缀
    private static final String TREE_CACHE_KEY = "photo_tree_cache";
    // 路径分隔符（目标JSON用\，统一固定避免跨平台差异）
    private static final String PATH_SEPARATOR = "\\";
    // 根目录配置（名称固定为"相片档案"，path固定为空字符串）
    private static final String ROOT_NAME = "相片档案";
    private static final String ROOT_PATH = "";

    /**
     * 批量处理图片路径，构建与目标JSON一致的树状结构
     * @param imagePaths 所有图片/文件的完整路径列表（如E:\相片档案\2025\9月\0901\军训\xxx.jpg）
     * @return 匹配目标格式的DocumentNode根节点
     */
    @Cacheable(value = TREE_CACHE_KEY, key = "#root.methodName", unless = "#result == null")
    public DocumentNode buildPhotoTree(List<String> imagePaths) {
        log.info("开始构建照片树，数据量: {}", imagePaths.size());
        long startTime = System.currentTimeMillis();

        // 1. 创建根节点（path为空字符串，directory=true）
        DocumentNode root = new DocumentNode(ROOT_NAME, ROOT_PATH, true);
        // 节点缓存：key=节点path，value=节点对象（避免重复创建）
        Map<String, DocumentNode> nodeCache = new HashMap<>();
        nodeCache.put(ROOT_PATH, root);

        // 2. 遍历所有路径，逐个构建节点
        for (String imagePath : imagePaths) {
            if (imagePath == null || imagePath.trim().isEmpty()) {
                log.warn("跳过空路径");
                continue;
            }

            // 解析路径：提取从"相片档案"开始的相对路径（如"相片档案\2025\9月\0901\军训\xxx.jpg"）
            String relativePath = getRelativePath(imagePath);
            if (relativePath == null) {
                log.warn("路径不包含根目录[{}]，跳过：{}", ROOT_NAME, imagePath);
                continue;
            }

            // 分割相对路径为片段（如["相片档案", "2025", "9月", "0901", "军训", "xxx.jpg"]）
            List<String> pathSegments = splitPathToSegments(relativePath);
            if (pathSegments.size() <= 1) {
                // 只有根目录，无子节点，跳过
                continue;
            }

            // 3. 构建当前路径的节点层级（从根目录的子节点开始）
            buildNodeHierarchy(pathSegments, nodeCache, root);
        }

        // 4. 对所有节点的子节点排序（目录在前，文件在后；按名称字母序）
        sortNodeChildren(root);

        long endTime = System.currentTimeMillis();
        log.info("照片树构建完成，耗时: {}ms", (endTime - startTime));
        return root;
    }

    /**
     * 处理单个图片路径，构建树状结构（重载方法）
     * @param imagePath 单个图片/文件的完整路径
     * @return 包含该路径的树状结构
     */
    public DocumentNode buildPhotoTree(String imagePath) {
        List<String> imagePaths = new ArrayList<>();
        if (imagePath != null) {
            imagePaths.add(imagePath);
        }
        return buildPhotoTree(imagePaths);
    }

    /**
     * 向已存在的树中添加单个路径（增量更新）
     * @param existingTree 已有的树根节点
     * @param imagePath 新增的图片/文件路径
     * @return 更新后的树
     */
    public DocumentNode addImageToTree(DocumentNode existingTree, String imagePath) {
        if (existingTree == null) {
            return buildPhotoTree(imagePath);
        }
        if (imagePath == null) {
            log.warn("图片路径为空，不添加");
            return existingTree;
        }

        // 加载已有节点到缓存
        Map<String, DocumentNode> nodeCache = new HashMap<>();
        loadExistingNodes(existingTree, nodeCache);

        // 解析路径并构建新节点
        String relativePath = getRelativePath(imagePath);
        if (relativePath == null) {
            log.warn("路径不包含根目录，跳过：{}", imagePath);
            return existingTree;
        }
        List<String> pathSegments = splitPathToSegments(relativePath);
        if (pathSegments.size() > 1) {
            buildNodeHierarchy(pathSegments, nodeCache, existingTree);
        }

        // 重新排序
        sortNodeChildren(existingTree);
        return existingTree;
    }

    // ------------------------------ 私有工具方法 ------------------------------

    /**
     * 提取从根目录（相片档案）开始的相对路径
     * 例：输入E:\相片档案\2025\9月\0901\军训\xxx.jpg → 输出"相片档案\2025\9月\0901\军训\xxx.jpg"
     */
    private String getRelativePath(String fullPath) {
        // 统一转换为小写，避免"相片档案"大小写差异（如"相片档案"和"照片档案"）
        String lowerFullPath = fullPath.toLowerCase();
        String lowerRootName = ROOT_NAME.toLowerCase();

        // 找到根目录在路径中的起始索引
        int rootStartIndex = lowerFullPath.indexOf(lowerRootName);
        if (rootStartIndex == -1) {
            return null;
        }

        // 截取从根目录开始的部分（保留原大小写）
        return fullPath.substring(rootStartIndex);
    }

    /**
     * 将相对路径分割为片段（按\或/分割，兼容Windows和Linux路径输入）
     * 例：输入"相片档案\2025\9月\0901\军训\xxx.jpg" → 输出["相片档案", "2025", "9月", "0901", "军训", "xxx.jpg"]
     */
    private List<String> splitPathToSegments(String relativePath) {
        List<String> segments = new ArrayList<>();
        // 用正则匹配\或/作为分隔符，兼容两种路径格式
        String[] rawSegments = relativePath.split("[\\\\/]");

        for (String segment : rawSegments) {
            // 过滤空片段（如路径开头/结尾的分隔符导致的空值）
            String trimmed = segment.trim();
            if (!trimmed.isEmpty()) {
                segments.add(trimmed);
            }
        }
        return segments;
    }

    /**
     * 构建节点层级（核心逻辑）
     * @param pathSegments 路径片段（如["相片档案", "2025", "9月", "0901", "军训", "xxx.jpg"]）
     * @param nodeCache 节点缓存（避免重复创建）
     * @param root 根节点
     */
    private void buildNodeHierarchy(List<String> pathSegments, Map<String, DocumentNode> nodeCache, DocumentNode root) {
        DocumentNode currentParent = root; // 当前父节点（从根开始）
        StringBuilder currentPath = new StringBuilder(); // 当前节点的path（如"2025\9月\0901"）

        // 遍历路径片段：跳过第一个片段（根目录），从子节点开始处理
        for (int i = 1; i < pathSegments.size(); i++) {
            String segmentName = pathSegments.get(i); // 当前片段名称（如"2025"、"9月"）
            boolean isDirectory = (i != pathSegments.size() - 1); // 最后一个片段是文件，其余是目录

            // 构建当前节点的path（如：i=1时→"2025"，i=2时→"2025\9月"）
            if (currentPath.length() > 0) {
                currentPath.append(PATH_SEPARATOR);
            }
            currentPath.append(segmentName);
            String nodePath = currentPath.toString();

            // 检查缓存：若节点已存在，直接复用；否则创建新节点
            if (nodeCache.containsKey(nodePath)) {
                currentParent = nodeCache.get(nodePath);
            } else {
                // 创建新节点（名称=片段名，path=当前构建的路径，directory=是否为目录）
                DocumentNode newNode = new DocumentNode(segmentName, nodePath, isDirectory);
                currentParent.getChildren().add(newNode); // 加入父节点的子列表
                nodeCache.put(nodePath, newNode); // 加入缓存
                currentParent = newNode; // 更新父节点，处理下一级
            }
        }
    }

    /**
     * 递归排序子节点：目录在前，文件在后；同类型按名称忽略大小写排序
     */
    private void sortNodeChildren(DocumentNode node) {
        if (node == null || node.getChildren().isEmpty()) {
            return;
        }

        // 排序规则：目录优先级高于文件；名称按字母序（忽略大小写）
        node.getChildren().sort((a, b) -> {
            if (a.isDirectory() && !b.isDirectory()) {
                return -1; // 目录在前
            } else if (!a.isDirectory() && b.isDirectory()) {
                return 1; // 文件在后
            } else {
                // 同类型：按名称忽略大小写比较
                return a.getName().compareToIgnoreCase(b.getName());
            }
        });

        // 递归排序子节点的子节点（深层排序）
        for (DocumentNode child : node.getChildren()) {
            sortNodeChildren(child);
        }
    }

    /**
     * 加载已有树的所有节点到缓存（用于增量更新）
     */
    private void loadExistingNodes(DocumentNode node, Map<String, DocumentNode> nodeCache) {
        if (node == null) {
            return;
        }
        nodeCache.put(node.getPath(), node);
        // 递归加载子节点
        for (DocumentNode child : node.getChildren()) {
            loadExistingNodes(child, nodeCache);
        }
    }

    /**
     * 清除照片树缓存（数据更新后调用）
     */
    @CacheEvict(value = TREE_CACHE_KEY, allEntries = true)
    public void clearTreeCache() {
        log.info("照片树缓存已全部清除");
    }


    @Cacheable(value = TREE_CACHE_KEY, key = "#rootPath", unless = "#result == null")
    public DocumentNode buildDocumentTree(String rootPath) throws IOException {
        Path root = Paths.get(rootPath);
        if (!Files.exists(root)) {
            throw new IllegalArgumentException("目录不存在: " + rootPath);
        }
        System.out.println("开始构建树...");
        return buildTree(root, root);
    }


    public DocumentNode buildTree(Path root, Path current) throws IOException {
        String name = current.getFileName().toString();
        String relativePath = root.relativize(current).toString();
        boolean isDirectory = Files.isDirectory(current);

        DocumentNode node = new DocumentNode(name, relativePath, isDirectory);

        if (isDirectory) {
            // 遍历目录并按文件名排序
            Files.list(current)
                    .sorted(Comparator.comparing(path -> path.getFileName().toString()))
                    .forEach(path -> {
                        try {
                            DocumentNode child = buildTree(root, path);
                            node.getChildren().add(child);
                        } catch (IOException e) {
                            // 处理异常或跳过
                        }
                    });
        }

        return node;
    }
}
